'use strict';
const dayjs = require("dayjs")
const request = require("request")
const crypto = require("crypto")
const { v4 } = require('uuid');
/** 本机认证服务身份证实人认证在线检测接口地址 */
const API_URL_SEND = "https://sms.dun.163.com/v2/sendsms"
const API_URL_VERIFY = "https://sms.dun.163.com/v2/verifysms"

class SMS {
    constructor({ secretId, secretKey } = {}, debug = false) {
        if (!secretId) throw new Error('secretId fail');
        if (!secretKey) throw new Error('secretKey fail');

        this.secretId = secretId;
        this.secretKey = secretKey;
        this.debug = debug;
    }
    /**
     * 发送短信验证码
     * @param mobile 手机号
     * @param code 短信内容
     * @param templateId 模板id
     * @param businessId 国内验证码短信 业务id
     * @return
     */
    async sendCode(mobile, code, templateId, businessId) {
        let json = code ? { code } : {}
        let data = this.getData(mobile, json, templateId, businessId)
        return this.postForm(API_URL_SEND, data)
    }

     /**
     * 发送自定义短信
     * @param mobile 手机号
     * @param json 短信内容
     * @param templateId 模板id
     * @param businessId 国内通知类短信 业务id
     * @return
     */
      async sendData(mobile, json, templateId, businessId) {
        let data = this.getData(mobile, json, templateId, businessId)
        return this.postForm(API_URL_SEND, data)
    }
    /**
     * 验证码校验
     * @param {*} requestId 短信发送接口返回的requestId字段
     * @param {*} code 用户填写的验证码
     * @returns 
     */
    async verify(requestId, code, businessId) {
        let data = this.getVerifyData(requestId, code, businessId)
        return this.postForm(API_URL_VERIFY, data)
    }

    log(...args) {
        if (this.debug) console.log(...args);
    }

    /**
     *  封装时间戳和签名机制(java以此验证访问是否合法)
     * @returns {{sign: *, timestamp: number}}
     */
    getVerifyData(requestId, code, businessId) {
        // 1.设置公共参数和随机字符串
        let timestamp = dayjs().valueOf();
        let nonce = v4().replace(/-/g, ''); // 去除横线-
        let data = { "secretId": this.secretId, businessId, "version": "v2", timestamp, nonce }
        // 2.设置私有参数
        data.requestId = requestId
        data.code = code
        // 3.生成签名信息
        data.signature = this.genSignature(this.secretKey, data)
        this.log(data)
        return data;
    }
    /**
     *  封装时间戳和签名机制(java以此验证访问是否合法)
     * @returns {{sign: *, timestamp: number}}
     */
    getData(mobile, json, templateId, businessId) {
        // 1.设置公共参数和随机字符串
        let timestamp = dayjs().valueOf();
        let nonce = v4().replace(/-/g, ''); // 去除横线-      
        let data = { "secretId": this.secretId, businessId, "version": "v2", timestamp, nonce }
        // 2.设置私有参数
        data.mobile = mobile;
        //使用JSON格式填充模板
        data.paramType = "json"
        data.params = JSON.stringify(json)
        data.templateId = templateId  //  模板id
        //使用验证码生成功能
        if (JSON.stringify(json) == "{}") {
            data.codeName = "code"
            data.codeLen = "6"
            data.codeValidSec = "300"
        } 
        // 3.生成签名信息
        data.signature = this.genSignature(this.secretKey, data)
        return data;
    }

    /**
     * 生成签名
     * @param secretKey
     * @param paramsJson
     * @returns {PromiseLike<ArrayBuffer>}
     */
    genSignature(secretKey, paramsJson) {
        const sorter = function (paramsJson) {
            const sortedJson = {};
            const sortedKeys = Object.keys(paramsJson).sort();
            for (let i = 0; i < sortedKeys.length; i++) {
                sortedJson[sortedKeys[i]] = paramsJson[sortedKeys[i]]
            }
            return sortedJson;
        };
        const sortedParam = sorter(paramsJson);
        let needSignatureStr = "";
        for (let key in sortedParam) {
            const value = sortedParam[key];
            needSignatureStr = needSignatureStr + key + value;
        }
        needSignatureStr += secretKey;
        const md5er = crypto.createHash('md5');//MD5加密工具
        md5er.update(needSignatureStr, "UTF-8");
        return md5er.digest('hex');
    };
    /**
     * 封装post请求
     * @param {*} url 
     * @param {*} requestData 
     * @returns 
     */
    async postForm(url, requestData){
        this.log("post: url " + url)
        this.log(requestData)
        let that = this
        return new Promise((resolve, reject)=>{
            const option ={
                url: url,
                method: "POST",
                headers: {
                    "content-type": "application/x-www-form-urlencoded",
                },
                form: requestData
            }
            request(option, function(error, response, body) {
                if (!error && response.statusCode == 200 ) {
                    that.log(body)
                    let o = JSON.parse(body)
                    if( o.code == 200 ) resolve(o)
                    else reject(o)
                }else{
                    reject(error);   // 返回错误信息
                }
            });
        });
    };
}

module.exports = SMS